/*
 * ---------------------------------------------------------------------
 * Copyright (c) 2014, 2015 All Right Reserved
 * This software is developed for study and improve coding skill ...
 *
 * Project:  Excellent Coding< EC >
 *
 * ecFileOP.cpp
 * This file for Common file operation interface implementation.
 *
 * Eamil:   epengao@126.com
 * Author:  Peter Gao
 * Version: Intial first version.
 * --------------------------------------------------------------------
 */

#include <stdio.h>
#include <string.h>
#include "ecFileOP.h"
#include "ecStringOP.h"

namespace ec {

ecFileOP::ecFileOP(EC_S32 nFD)
:m_nFD(nFD)
,m_pFile(EC_NULL)
,m_pFilePath(EC_NULL)
{
}

ecFileOP::ecFileOP(const EC_PCHAR pFilePath)
:m_nFD(-1)
,m_pFile(EC_NULL)
{
    EC_U32 nSize = ecStrLen(pFilePath);
    m_pFilePath = new EC_CHAR[nSize+1];
    if(m_pFilePath)
        ecStrCopy(m_pFilePath, pFilePath);
}

ecFileOP::~ecFileOP()
{
    if(m_pFilePath)
        delete m_pFilePath;
    if(m_pFile)
        fclose(m_pFile);
}

EC_U32 ecFileOP::Open(const EC_PCHAR pOpenType)
{
    EC_U32 nRet = EC_Err_None;
    if(EC_NULL == m_pFile)
    {
        if(m_nFD >= 0)
        {
            m_pFile = fdopen(m_nFD, pOpenType);
            if(m_pFile)
                nRet = EC_Err_None;
            else
                nRet = EC_Err_FileOpenFaild;
        }
        else if(m_pFilePath)
        {
            m_pFile = fopen(m_pFilePath, pOpenType);
            if(EC_NULL == m_pFile)
                nRet = EC_Err_FileOpenFaild;
        }
        else
            nRet = EC_Err_FileOpenFaild;
    }

    return nRet;
}

EC_U32 ecFileOP::Close()
{
    if(m_pFile)
    {
        fclose(m_pFile);
        m_pFile = EC_NULL;
    }

    return EC_Err_None;
}

EC_LONG ecFileOP::GetSize()
{
    EC_LONG nRet = 0;
    if(m_pFile)
    {
        EC_LONG nCurr = ftell(m_pFile);
        fseek(m_pFile, 0L, EC_FILE_SEEK_END);
        nRet = ftell(m_pFile);
        fseek(m_pFile, nCurr, EC_FILE_SEEK_SET);
    }
    return nRet;
}

EC_U32 ecFileOP::GetPath(EC_PCHAR pPathOut)
{
#ifdef _LINUX
    if(EC_NULL == pPathOut)
        return EC_Err_BadParam;

    EC_U32 nFD = -1;
    EC_U32 nRet = EC_Err_None;
    if(m_pFilePath)
    {
        ecStrCopy(pPathOut, m_pFilePath);
        return nRet;
    }

    if(m_pFile)
        nFD = fileno(m_pFile);
    else if(m_nFD >= 0)
        nFD = m_nFD;
    else
        nRet = EC_Err_DataNotExist;

    if(nFD >= 0)
    {
        EC_CHAR pBuf[EC_FILE_MAX_PATH] = {0};  
        EC_CHAR pFilePath[EC_FILE_MAX_PATH] = {0};
        snprintf(pBuf, sizeof(pBuf), "/proc/%ld/fd/%d", (EC_LONG)getpid(), nFD);  
        if (readlink(pBuf, pFilePath, EC_FILE_MAX_PATH-1) != -1)
            ecStrCopy(pPathOut, pFilePath);
    }

    return nRet;
#endif

    if(m_pFilePath)
    {
        ecStrCopy(pPathOut, m_pFilePath);
    }
    return EC_Err_None;
}

EC_U32 ecFileOP::Flush()
{
    if(m_pFile)
    {
        fflush(m_pFile);
        return EC_Err_None;
    }

    return EC_Err_OperatorFaild;
}

EC_CHAR ecFileOP::ReadChar()
{
    if(m_pFile)
        return fgetc(m_pFile);
    
    return EC_FILE_EOF;
}

EC_U32 ecFileOP::WriteChar(EC_CHAR cChar)
{
    if(m_pFile)
    {
        fputc(cChar, m_pFile);
        return EC_Err_None;
    }

    return EC_Err_OperatorFaild;
}

EC_U32 ecFileOP::ReadStrLine(EC_PCHAR pStr, EC_U32 nSize)
{
    if(m_pFile)
    {
        EC_PCHAR pRet = fgets(pStr, nSize, m_pFile);
        if(pRet)
            return EC_Err_None;
    }

    return EC_Err_OperatorFaild;
}

EC_U32 ecFileOP::ReadBuffer(EC_BUFFER pBuf, EC_U32 nBufSize, EC_U32 nBufCount)
{
    if(m_pFile)
    {
        fread(pBuf, nBufSize, nBufCount, m_pFile);
        return EC_Err_None;
    }

    return EC_Err_OperatorFaild;
}

EC_U32 ecFileOP::WriteBuffer(EC_BUFFER pBuf, EC_U32 nBufSize, EC_U32 nBufCount)
{
    if(m_pFile)
    {
        fwrite(pBuf, nBufSize, nBufCount, m_pFile);
        return EC_Err_None;
    }

    return EC_Err_OperatorFaild;
}

EC_U32 ecFileOP::Seek(EC_S32 nOffset, EC_U32 nFromPos)
{
    if(m_pFile)
    {
        fseek(m_pFile, nOffset, nFromPos);
        return EC_Err_None;
    }

    return EC_Err_OperatorFaild;
}

} /* namespace ec */